package com.yanqu.road.server.manager.marriage;

import com.yanqu.road.entity.enums.eMarriageStatusType;
import com.yanqu.road.entity.enums.eSexType;
import com.yanqu.road.entity.marriage.MarriageInfo;
import com.yanqu.road.entity.union.cross.CrossUnionMember;
import com.yanqu.road.logic.bussiness.marriage.CrossMarriageBusiness;
import com.yanqu.road.logic.config.GameConfig;
import com.yanqu.road.logic.pb.MarriagePb;
import com.yanqu.road.message.YanQuMessage;
import com.yanqu.road.pb.marriage.CrossMarriageProto;
import com.yanqu.road.server.TempMgr;
import com.yanqu.road.server.logic.MessageHelper;
import com.yanqu.road.server.manager.union.CrossUnionMgr;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.server.protocol.Protocol;
import com.yanqu.road.utils.YanQuMessageUtils;
import com.yanqu.road.utils.string.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 玩家跨服联姻管理类
 */
public class CrossUnionMarriageMgr extends TempMgr {

    private static Logger logger = LogManager.getLogger(CrossUnionMarriageMgr.class.getName());

    /**
     * 子嗣编号，子嗣数据
     */
    private static Map<String, MarriageInfo> allMarriageMap = new ConcurrentHashMap<>();
    //商会、性别、uid
    private static Map<String, Map<Integer, Map<String, MarriageInfo>>> unionApplyMap = new ConcurrentHashMap<>();

    private static Object locker = new Object();

    @Override
    public boolean init() throws Exception {
        return reload();
    }

    @Override
    public boolean reloadConfig() throws Exception {
        return true;
    }

    @Override
    public boolean stop() {
        return false;
    }

    @Override
    public boolean reloadData() {
        synchronized (locker) {
            allMarriageMap = CrossMarriageBusiness.getMarriageInfoMap();
            initMarriageApply();
        }
        return true;
    }

    @Override
    public boolean save() {
        Set<String> needRemoveList = new HashSet<>();
        int waitNum = 0;
        for(MarriageInfo marriageInfo : allMarriageMap.values()){
            if(marriageInfo.isInsertOption()){
                CrossMarriageBusiness.addMarriageInfo(marriageInfo);
            }else if(marriageInfo.isUpdateOption()){
                CrossMarriageBusiness.updateMarriageInfo(marriageInfo);
            }
            if (marriageInfo.getStatus() == eMarriageStatusType.MARRIED && !marriageInfo.isDirty()) {
                needRemoveList.add(marriageInfo.getChildUid());
            }else if (marriageInfo.getStatus() == eMarriageStatusType.WAIT && !marriageInfo.isDirty()) {
                waitNum++;
            }

            if (marriageInfo.getStatus() == eMarriageStatusType.WAIT && !marriageInfo.isDirty() ) {
                if (System.currentTimeMillis() / 1000 - marriageInfo.getPublishTime() > (GameConfig.MARRIAGE_PUBLISH_TIME + 24 *3600)) {
                    needRemoveList.add(marriageInfo.getChildUid());
                }
            }
        }
        int removeSize = 0;
        for (String childUid : needRemoveList) {
            synchronized (allMarriageMap) {
                MarriageInfo marriageInfo = allMarriageMap.get(childUid);
                if (marriageInfo != null) {
                    if(marriageInfo.getStatus() == eMarriageStatusType.MARRIED){
                        allMarriageMap.remove(childUid);
                        removeSize++;
                    }else {
                        if(marriageInfo.getStatus() == eMarriageStatusType.WAIT && !marriageInfo.isDirty()) {
                            if (System.currentTimeMillis() / 1000 - marriageInfo.getPublishTime() > (GameConfig.MARRIAGE_PUBLISH_TIME + 24 * 3600)) {
                                allMarriageMap.remove(childUid);
                                removeSize++;
                            }
                        }
                    }
                }
            }
        }

        try{
            int applyNum = 0;
            int removeNum = 0;
            int notInAll = 0;
            int marriedNum = 0;
            for(Map<Integer, Map<String, MarriageInfo>> sexMap : unionApplyMap.values()){
                for(Map<String, MarriageInfo> dataMap : sexMap.values()){
                    List<String> removeList = new ArrayList<>();
                    for (MarriageInfo marriageInfo : dataMap.values()) {
                        if (!allMarriageMap.containsKey(marriageInfo.getChildUid())) {
                            notInAll++;
                        }
                        if (marriageInfo.getStatus() == eMarriageStatusType.MARRIED) {
                            marriedNum++;
                        }
                        if (marriageInfo.getStatus() == eMarriageStatusType.MARRIED) {
                            removeList.add(marriageInfo.getChildUid());
                            removeNum++;
                        }else {
                            applyNum++;
                        }
                    }
                    for(String keyStr : removeList){
                        dataMap.remove(keyStr);
                    }
                }
            }
            getLogger().info("all marriage size:  {}, wait size: {}, removeSize: {}, applyNum: {}, removeNum: {}, notInAll: {}, marriedNum: {}", allMarriageMap.size(),waitNum,removeSize, applyNum, removeNum,notInAll,marriedNum);
        }catch (Exception e){
            logger.error("clear unionApply error:", e);
        }


        return true;
    }

    private static void initMarriageApply() {
        synchronized (locker) {
            Map<String, Map<Integer, Map<String, MarriageInfo>>> tempUnionApplyMap = new ConcurrentHashMap<>();
            for (MarriageInfo data : allMarriageMap.values()) {
                if (data.getStatus() == eMarriageStatusType.UnionApply) {//如果是发布联姻状态
                    if (isOverApplyTime(data)) {
                        data.setStatus(eMarriageStatusType.WAIT);
                    } else {
                        CrossUnionMember crossUnionMember = CrossUnionMgr.getUnionMemberByUserId(data.getUserId());
                        if(null == crossUnionMember){
                            data.setStatus(eMarriageStatusType.WAIT);
                        }else {
                            String unionUid = crossUnionMember.getUnionUid();
                            if(StringUtils.isNullOrEmpty(unionUid)){
                                data.setStatus(eMarriageStatusType.WAIT);
                            }else {
                                if (!tempUnionApplyMap.containsKey(unionUid)) {
                                    tempUnionApplyMap.put(unionUid, new ConcurrentHashMap<>());
                                }
                                Map<Integer, Map<String, MarriageInfo>> sexMap = tempUnionApplyMap.get(unionUid);
                                if (!sexMap.containsKey(data.getChildSex())) {
                                    sexMap.put(data.getChildSex(), new ConcurrentHashMap<>());
                                }
                                Map<String, MarriageInfo> dataMap = sexMap.get(data.getChildSex());
                                dataMap.put(data.getChildUid(), data);
                            }
                        }
                    }
                }
            }
            unionApplyMap = tempUnionApplyMap;
        }
    }

    /**
     * 发布商会联姻
     *
     * @param userId
     * @param marriageInfo
     * @return
     */
    public static int publishUnionMarriage(long userId, MarriageInfo marriageInfo) {
        CrossUnionMember crossUnionMember = CrossUnionMgr.getUnionMemberByUserId(userId);
        if(null == crossUnionMember){
            return GameErrorCode.E_UNION_NO_JOIN_UNION;
        }
        String unionUid = crossUnionMember.getUnionUid();
        if(StringUtils.isNullOrEmpty(unionUid)){
            return GameErrorCode.E_UNION_NO_JOIN_UNION;
        }
        if(!unionApplyMap.containsKey(unionUid)){
            synchronized (unionApplyMap){
                if(!unionApplyMap.containsKey(unionUid)){
                    unionApplyMap.put(unionUid, new ConcurrentHashMap<>());
                }
            }
        }
        Map<Integer, Map<String, MarriageInfo>> sexMap = unionApplyMap.get(unionUid);
        if(!sexMap.containsKey(marriageInfo.getChildSex())){
            synchronized (sexMap){
                if(!sexMap.containsKey(marriageInfo.getChildSex())){
                    sexMap.put(marriageInfo.getChildSex(), new ConcurrentHashMap<>());
                }
            }
        }
        Map<String, MarriageInfo> dataMap = sexMap.get(marriageInfo.getChildSex());
        synchronized (dataMap) {
            if(getUserPublishUnionApplyCount(userId, sexMap) >= GameConfig.UNION_CHILDREN_APPLY_MARRIAGE_LIMIT_MAX_COUNT){
                MarriageInfo old = dataMap.get(marriageInfo.getChildUid());
                if(old != null && old.getStatus() == eMarriageStatusType.UnionApply){
                    old.setPublishTime(System.currentTimeMillis() / 1000);
                    return 0;
                }
                return GameErrorCode.E_MARRIAGE_UNION_APPLY_COUNT_OVER;
            }
            marriageInfo.setStatus(eMarriageStatusType.UnionApply);
            MarriageInfo tempMarriage = putMarriage(marriageInfo);
            dataMap.put(marriageInfo.getChildUid(), tempMarriage);
        }
        return 0;
    }

    /**
     * 获取玩家商会联姻数量
     * @param userId
     * @return
     */
    private static int getUserPublishUnionApplyCount(long userId, Map<Integer, Map<String, MarriageInfo>> applyMap){
        if(null == applyMap){
            return 0;
        }
        int count = 0;
        for(Map<String, MarriageInfo> dataMap : applyMap.values()){
            List<MarriageInfo> dataList = new ArrayList<>(dataMap.values());
            for (MarriageInfo marriageInfo : dataList) {
                if (marriageInfo.getStatus() == eMarriageStatusType.UnionApply
                        && marriageInfo.getUserId() == userId
                        && !isOverApplyTime(marriageInfo)) {
                    count++;
                }
            }
        }
        return count;
    }

    /**
     * 把联姻放到内存
     *
     * @param marriageInfo
     * @return
     */
    private static MarriageInfo putMarriage(MarriageInfo marriageInfo) {
        MarriageInfo tempMarriage;
        if (!allMarriageMap.containsKey(marriageInfo.getChildUid())) {
            synchronized (allMarriageMap) {
                if (!allMarriageMap.containsKey(marriageInfo.getChildUid())) {
                    marriageInfo.setInsertOption();
                    allMarriageMap.put(marriageInfo.getChildUid(), marriageInfo);
                    tempMarriage = marriageInfo;
                } else {
                    tempMarriage = allMarriageMap.get(marriageInfo.getChildUid());
                    MarriagePb.cloneMarriage(tempMarriage, marriageInfo);
                }
            }
        } else {
            tempMarriage = allMarriageMap.get(marriageInfo.getChildUid());
            MarriagePb.cloneMarriage(tempMarriage, marriageInfo);
        }
        return tempMarriage;
    }

    /**
     * 获取商会联姻列表
     */
    public static List<MarriageInfo> getUnionApplyList(long userId, int childSex) {
        List<MarriageInfo> dataList = new ArrayList<>();

        CrossUnionMember crossUnionMember = CrossUnionMgr.getUnionMemberByUserId(userId);
        if(null == crossUnionMember){
            return dataList;
        }
        String unionUid = crossUnionMember.getUnionUid();
        if(StringUtils.isNullOrEmpty(unionUid)){
            return dataList;
        }
        Map<Integer, Map<String, MarriageInfo>> sexMap = unionApplyMap.get(unionUid);
        if(null == sexMap){
            return dataList;
        }
        int getSex;
        if(childSex == eSexType.MALE.getValue()){
            getSex = eSexType.FEMALE.getValue();
        }else {
            getSex = eSexType.MALE.getValue();
        }
        Map<String, MarriageInfo> dataMap = sexMap.get(getSex);
        if (dataMap != null) {
            for (MarriageInfo marriageInfo : dataMap.values()) {
                if (marriageInfo.getStatus() == eMarriageStatusType.UnionApply
                        && marriageInfo.getUserId() != userId
                        && !isOverApplyTime(marriageInfo)
                ) {//未联姻商会联姻申请
                    dataList.add(marriageInfo);
                }
            }
        }
        return dataList;
    }

    /**
     * 处理联姻请求
     * @param userId 同意联姻的玩家
     * @param marriageInfo 联姻信息(同意者)
     * @param partnerChildUid 申请联姻的玩家子嗣
     * @return
     */
    public static int agreeMarriage(long userId, MarriageInfo marriageInfo, String partnerChildUid) {
        MarriageInfo partnerMarriage = allMarriageMap.get(partnerChildUid);
        if (null == partnerMarriage) {
            return GameErrorCode.E_MARRIAGE_APPLY_NO_FOUND;
        }
        if (partnerMarriage.getUserId() == userId) {
            return GameErrorCode.E_MARRIAGE_NO_SELF;
        }
        CrossUnionMember crossUnionMember = CrossUnionMgr.getUnionMemberByUserId(userId);
        if(null == crossUnionMember){
            return GameErrorCode.E_CROSS_MARRIAGE_NO_SAME_UNION;
        }
        String unionUid = crossUnionMember.getUnionUid();
        CrossUnionMember partnerUnionMember = CrossUnionMgr.getUnionMemberByUserId(partnerMarriage.getUserId());
        if(null == partnerUnionMember || !Objects.equals(unionUid, partnerUnionMember.getUnionUid())){
            return GameErrorCode.E_CROSS_MARRIAGE_NO_SAME_UNION;
        }
        //检查双方性别 等等
        if (marriageInfo.getChildSex() == partnerMarriage.getChildSex()) {
            return GameErrorCode.E_MARRIAGE_SEX_WRONG;
        }
        //判断是否过期
        if (isOverApplyTime(partnerMarriage)) {
            return GameErrorCode.E_MARRIAGE_IS_OVER_TIME;
        }
        //判断发布状态
        if (partnerMarriage.getStatus() != eMarriageStatusType.UnionApply) {
            return GameErrorCode.E_MARRIAGE_STATE_NO_APPLY;
        }

        CrossMarriageProto.CrossMarriageAgreeCrossDealReqMsg.Builder dealMsg = CrossMarriageProto.CrossMarriageAgreeCrossDealReqMsg.newBuilder();
        dealMsg.setApplyData(MarriagePb.parseMarriageApplyTempMsg(marriageInfo));
        dealMsg.setPartnerChildUid(partnerChildUid);
        YanQuMessage pbMsg = YanQuMessageUtils.buildMessage(Protocol.S_CROSS_UNION_MARRIAGE_TO_PARTNER_DEAL_AGREE, dealMsg);
        MessageHelper.sendPacket(partnerMarriage.getServerId(), partnerMarriage.getUserId(), pbMsg);
        return 0;
    }

    /**
     * 对方联姻处理完，来最终修改状态
     *
     * @param partnerChildUid
     */
    public static void agreeMarriageFinalDeal(String partnerChildUid) {
        MarriageInfo tempMarriage = allMarriageMap.get(partnerChildUid);
        if(null != tempMarriage) {
            synchronized (locker) {
                if (tempMarriage.getStatus() == eMarriageStatusType.UnionApply) {
                    tempMarriage.setStatus(eMarriageStatusType.MARRIED);
                }
            }
        }
    }

    /**
     * 取消跨服联姻
     *
     * @param childUid
     * @return
     */
    public static int cancelMarriage(long userId, String childUid) {
        CrossUnionMember crossUnionMember = CrossUnionMgr.getUnionMemberByUserId(userId);
        if(null == crossUnionMember){
            return GameErrorCode.E_UNION_NO_JOIN_UNION;
        }
        String unionUid = crossUnionMember.getUnionUid();
        if(StringUtils.isNullOrEmpty(unionUid)){
            return GameErrorCode.E_UNION_NO_JOIN_UNION;
        }
        return cancelMarriage(unionUid, childUid);
    }

    /**
     * 取消跨服联姻
     *
     * @param childUid
     * @return
     */
    public static int cancelMarriage(String unionUid, String childUid) {
        MarriageInfo marriageInfo = allMarriageMap.get(childUid);
        if (null == marriageInfo) {
            return GameErrorCode.E_MARRIAGE_CHILD_NO_FOUND;
        }
        if (marriageInfo.getStatus() == eMarriageStatusType.MARRIED) {
            return GameErrorCode.E_MARRIAGE_ALREADY_MARRY;
        }

        if (marriageInfo.getStatus() == eMarriageStatusType.UnionApply) {
            if(!StringUtils.isNullOrEmpty(unionUid)){
                Map<Integer, Map<String, MarriageInfo>> sexMap = unionApplyMap.get(unionUid);
                if(null != sexMap){
                    Map<String, MarriageInfo> dataMap = sexMap.get(marriageInfo.getChildSex());
                    if(null != dataMap){
                        dataMap.remove(marriageInfo.getChildUid());
                    }
                }
            }
            synchronized (locker) {
                if (marriageInfo.getStatus() == eMarriageStatusType.UnionApply) {
                    marriageInfo.setStatus(eMarriageStatusType.WAIT);
                }
            }
        }
        return 0;
    }

    /**
     * 发布时间是否超时
     */
    private static boolean isOverApplyTime(MarriageInfo marriageInfo) {
        return System.currentTimeMillis() / 1000 - marriageInfo.getPublishTime() > GameConfig.MARRIAGE_PUBLISH_TIME;
    }

    /**
     * 处理超时的联姻
     *
     * @param childUid
     */
    public static void dealMarriageOverTime(String childUid) {
        MarriageInfo marriageInfo = allMarriageMap.get(childUid);
        if (null == marriageInfo) {
            return;
        }
        synchronized (locker) {
            if (marriageInfo.getStatus() == eMarriageStatusType.UnionApply) {
                marriageInfo.setAppointUserId(0);
                marriageInfo.setPartnerServerId(0);
                marriageInfo.setStatus(eMarriageStatusType.WAIT);
            }
        }
    }
}
